#region File Description
//-----------------------------------------------------------------------------
// LoadingScreen.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
#endregion

namespace ScreenManagement
{
    /// <summary>
    /// The loading screen coordinates transitions between the menu system and the
    /// game itself. Normally one screen will transition off at the same time as
    /// the next screen is transitioning on, but for larger transitions that can
    /// take a longer time to load their data, we want the menu system to be entirely
    /// gone before we start loading the game. This is done as follows:
    /// 
    /// - Tell all the existing screens to transition off.
    /// - Activate a loading screen, which will transition on at the same time.
    /// - The loading screen watches the state of the previous screens.
    /// - When it sees they have finished transitioning off, it activates the real
    ///   next screen, which may take a long time to load its data. The loading
    ///   screen will be the only thing displayed while this load is taking place.
    /// </summary>
    class LoadingScreen : GameScreen
    {
        #region Fields

        bool loadingIsSlow;
        bool otherScreensAreGone;
        static bool userContinue = false;

        ContentManager content;
        Texture2D aButton, dPad;
        SpriteFont spriteFont;

        int selectedHint;
        static readonly string[] preloadAssets =
        {
            "Rotate the board display by using the left, right and \nup on right thumbstick.",
            "In Shafran, castling can occur under the normal \ncircumstances. It is not available in Glinski and McCooey.",
            "En passant is possible in all versions, according to the normal rules.",
            "There are multiple move suggestions options to change \nwith up on the D-Pad. Availabe moves with threats, \navailable only and none.",
            "Multiplayer can be played locally with a single controller.",
            "Toggle display modes in game using down on the D-Pad. \nModes are: Last move and 50-move count and threefold repetition,\nLast move,\nnone.",
            "In single player, the AI can think for 5 seconds on easy,\n10 seconds on medium and 15 seconds on hard.",
        };

        GameScreen[] screensToLoad;

        #endregion

        #region Initialization


        /// <summary>
        /// The constructor is private: loading screens should
        /// be activated via the static Load method instead.
        /// </summary>
        private LoadingScreen(ScreenManager screenManager, bool loadingIsSlow,
                              GameScreen[] screensToLoad)
        {
            this.loadingIsSlow = loadingIsSlow;
            this.screensToLoad = screensToLoad;

            TransitionOnTime = TimeSpan.FromSeconds(0.2);
            TransitionOffTime = TimeSpan.FromSeconds(0.2);

            Random rand = new Random();
            selectedHint = rand.Next(0, preloadAssets.Length);

            if (content == null)
                content = new ContentManager(screenManager.Game.Services, "Content");

            aButton = content.Load<Texture2D>("Textures/xboxControllerButtonA");
            dPad = content.Load<Texture2D>("Textures/xboxControllerDPad");
            spriteFont = screenManager.Font;
        }


        /// <summary>
        /// Activates the loading screen.
        /// </summary>
        public static void Load(ScreenManager screenManager, bool loadingIsSlow,
                                PlayerIndex? controllingPlayer,
                                bool coninueWithoutHumanInput,
                                params GameScreen[] screensToLoad)
        {
            userContinue = coninueWithoutHumanInput;

            // Tell all the current screens to transition off.
            foreach (GameScreen screen in screenManager.GetScreens())
                screen.ExitScreen();

            // Create and activate the loading screen.
            LoadingScreen loadingScreen = new LoadingScreen(screenManager,
                                                            loadingIsSlow,
                                                            screensToLoad);

            screenManager.AddScreen(loadingScreen, controllingPlayer);
        }


        #endregion

        #region Update and Draw


        /// <summary>
        /// Updates the loading screen.
        /// </summary>
        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
                                                       bool coveredByOtherScreen)
        {
            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);

            // If all the previous screens have finished transitioning
            // off, it is time to actually perform the load.
            if (otherScreensAreGone)// && userContinue)
            {
                //ScreenManager.RemoveScreen(this);

                // TODO this only loads AFTER the user has hit continue... we need to load THEN allow the user to continue...
                foreach (GameScreen screen in screensToLoad)
                {
                    if (screen != null)
                    {
                        // only true when passed from exiting gameplay screen
                        if (userContinue)
                        {
                            ScreenManager.AddScreen(screen, ControllingPlayer);
                        }
                        else if (!screen.IsLoaded)
                        {
                            // Copied from add screen
                            screen.ControllingPlayer = this.ControllingPlayer;
                            screen.ScreenManager = this.ScreenManager;
                            screen.IsExiting = false;
                            screen.LoadContent();
                        }
                    }
                }

                // only true when passed from exiting gameplay screen.
                if (userContinue)
                    ScreenManager.RemoveScreen(this);

                // Once the load has finished, we use ResetElapsedTime to tell
                // the  game timing mechanism that we have just finished a very
                // long frame, and that it should not try to catch up.
                ScreenManager.Game.ResetElapsedTime();
            }
        }


        /// <summary>
        /// Draws the loading screen.
        /// </summary>
        public override void Draw(GameTime gameTime)
        {
            // If we are the only active screen, that means all the previous screens
            // must have finished transitioning off. We check for this in the Draw
            // method, rather than in Update, because it isn't enough just for the
            // screens to be gone: in order for the transition to look good we must
            // have actually drawn a frame without them before we perform the load.
            if ((ScreenState == ScreenState.Active) &&
                (ScreenManager.GetScreens().Length == 1))
            {
                otherScreensAreGone = true;
            }

            // The gameplay screen takes a while to load, so we display a loading
            // message while that is going on, but the menus load very quickly, and
            // it would look silly if we flashed this up for just a fraction of a
            // second while returning from the game to the menus. This parameter
            // tells us how long the loading is going to take, so we know whether
            // to bother drawing the message.
            if (loadingIsSlow)
            {
                SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
                SpriteFont font = ScreenManager.Font;

                string message = "Loading...\n\nHint:\n" + preloadAssets[selectedHint];

                // Center the text in the viewport.
                Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
                Vector2 viewportSize = new Vector2(viewport.Width, viewport.Height);
                Vector2 textSize = font.MeasureString(message);
                Vector2 textPosition = (viewportSize - textSize) / 2;

                Color color = Color.White * TransitionAlpha;

                // Draw the text.
                spriteBatch.Begin();
                spriteBatch.DrawString(font, message, textPosition, color);

                if (otherScreensAreGone && !userContinue)
                {
                    ScreenManager.SpriteBatch.Draw(dPad, new Rectangle(128, 720 - 72 - 84, 64, 64), color);
                    ScreenManager.SpriteBatch.DrawString(spriteFont, "Display Next Hint", new Vector2(128 + 128, 720 - 72 + 21 - 84), color);

                    ScreenManager.SpriteBatch.Draw(aButton, new Rectangle(1280 - 128 - 84, 720 - 72 - 84, 64, 64), color);
                    ScreenManager.SpriteBatch.DrawString(spriteFont, "Continue...", new Vector2(1280 - 128 - 84 - (int)spriteFont.MeasureString("Continue...  ").X, 720 - 72 + 21 - 84), color);
                }

                spriteBatch.End();
            }
        }

        public override void HandleInput(HexChessBoard.PlayerComponents.InputState input, GameTime gameTime)
        {
            if (this.ControllingPlayer != null)
            {
                if (otherScreensAreGone)
                {
                    if ((input.CurrentKeyboardStates[(int)this.ControllingPlayer].IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Enter) || input.CurrentGamePadStates[(int)this.ControllingPlayer].IsButtonDown(Microsoft.Xna.Framework.Input.Buttons.A)))
                    {
                        userContinue = true;

                        ScreenManager.RemoveScreen(this);

                        // TODO this only loads AFTER the user has hit continue... we need to load THEN allow the user to continue...
                        foreach (GameScreen screen in screensToLoad)
                        {
                            if (screen != null)
                            {
                                //ScreenManager.AddScreen(screen, ControllingPlayer);

                                // Copied from add screen
                                //screen.ControllingPlayer = this.ControllingPlayer;
                                //screen.ScreenManager = this.ScreenManager;
                                //screen.IsExiting = false;
                                //screen.LoadContent();

                                this.ScreenManager.screens.Add(screen);
                            }
                        }

                        // Once the load has finished, we use ResetElapsedTime to tell
                        // the  game timing mechanism that we have just finished a very
                        // long frame, and that it should not try to catch up.
                        ScreenManager.Game.ResetElapsedTime();
                    }
                    if (input.IsNewButtonPress(Microsoft.Xna.Framework.Input.Buttons.DPadRight, this.ControllingPlayer) || input.IsNewKeyPress(Microsoft.Xna.Framework.Input.Keys.Right, this.ControllingPlayer))
                    {
                        selectedHint++;
                        if (selectedHint >= preloadAssets.Length)
                            selectedHint = 0;
                    }
                }
            }
        }


        #endregion
    }
}
